目標:
上一個篇章我們岔出去說了一下 MongoDB,現在我們再回到 GrpahQL
有寫過 ApolloGraphQL 的讀者應該對於下面幾個名詞不陌生
它們有著密不可分的關係,所以我把它們放在一起說
Resolver | Schema | Queries |
---|---|---|
根據 Schema 的需求來實作 | 定義資料結構,客戶端可以讀取和寫入資料類型 | 包含 query 及 mutation,提供客戶端查詢以及更改資料的介面 |
NestJs 提供兩種方式建置 Schema
Code first | Schema first |
---|---|
透過 TypeScript classes 和 TypeScript decorators 生成 SDL,再透過 @nestjs/graphql 讀取定義好的 metadata ,自動生成 GraphQL Schema | 這方式可能是較為熟悉的方式,跟過去在定義 Schema 一樣,最後再需要的地方補上一些 decorators |
以上是兩個粗略的比較,接下來會以範例來說明,讓讀者能夠更明白兩者的差異 |
讀者可以開兩個專案,將其分開架構才不會過於混亂
之前 GraphQL 的範例是以 Schema first 編寫
首先使用 decorators 和 TypeScript classes 生成 GraphQL Schema,並指定路徑寫入
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { AuthorsModule } from './authors/authors.module';
import { join } from 'path';
@Module({
imports: [
GraphQLModule.forRoot({
// 將編譯過後的 Schema 寫入 src/schema.gql
autoSchemaFile: join(process.cwd(), 'src/schema.gql')
}),
AuthorsModule
]
})
export class AppModule {}
接著定義 Schema ,建立 author.model.ts,使用 TypeScript classes 和 TypeScript decorators 的 annotate ,標記屬性在欄位上。
在編譯時會根據 metadata 的屬性轉成相對的格式,我相信沒做過的人大概看不懂這是什麼意思,我們由範例來解說!
定義資料格式,包括:欄位名稱,類別,型態...
// 目錄: src/authors/models/author.model.ts
import { Field, ObjectType, ID } from '@nestjs/graphql';
@ObjectType()
export class Author {
@Field(type => ID)
id: string;
@Field({ nullable: true })
firstName?: string;
@Field({ nullable: true })
lastName?: string;
}
在 Resolver 中定義 查詢 author 方法,能傳入參數 id,為了指定此方法是 查詢 ,必須在名稱上面加上 @Query() decorator,最後 decorator 會基於方法名稱產生 Schema
// 目錄:src/authors/authors.resolver.ts
import { Resolver, Query, ID, Args } from "@nestjs/graphql";
import { Author } from './models/author.model';
@Resolver(of => Author)
export class AuthorsResolver {
constructor(
) {}
@Query(returns => Author)
async author(@Args('id', { type: () => ID }) id: string) {}
}
將剛剛完成的 Resolver import 到 authors.module
// 目錄:src/authors/authors.module.ts
import { Module } from '@nestjs/common';
import { AuthorsResolver } from './authors.resolver';
@Module({
providers: [AuthorsResolver]
})
export class AuthorsModule {}
接著先啟動服務,就能看到 src 目錄下生成了 schema.gql,這就是透過 TypeScript decorator 編譯完成的結果!
# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------
type Author {
id: ID!
firstName: String
lastName: String
}
type Query {
author(id: ID!): Author!
}
打開 http://localhost:3000/graphql ,查詢 author ,就會回傳失敗!!
因為 author 並沒有回傳任何物件,所以必須先回去 AuthorsResolver 補上要回傳的資訊,記得要符合我們定義的 author.model 格式。
async findOneById(id: String): Promise<Author> {
return {
id: '1',
lastName: "lastName",
firstName: "firstName"
};
}
最後完成的結果
下一篇章我們會說明 Schema first 是如何建構的~